home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-09-02 | 17.4 KB | 696 lines | [TEXT/KAHL] |
- /****
- * CNeoBenchDoc.c
- *
- * Document methods for a typical application.
- *
- * Copyright © 1990 Symantec Corporation. All rights reserved.
- *
- ****/
-
- #include "NeoTypes.h"
- #include "Global.h"
- #include "Commands.h"
- #include "CBartender.h"
- #include "CDecorator.h"
- #include "CDesktop.h"
- #include "CError.h"
- #include "CScrollPane.h"
- #include "CNeoBenchApp.h"
- #include "CNeoBenchDoc.h"
- #include "CNeoBenchPane.h"
- #include <Packages.h>
- #include <CWindow.h>
- #include <stdlib.h>
- #include CNeoDatabaseNativeH
- #include CNeoIndexIteratorH
- #include CNeoMetaClassH
- #include "CFiller.h"
-
- #define WINDNeoBench 500 /* Resource ID for WIND template */
-
- extern CBartender * gBartender; /* The menu handling object */
- extern CDecorator * gDecorator; /* Window dressing object */
- extern CDesktop * gDesktop; /* The enclosure for all windows */
-
- #ifdef qNeoThreads
- static short default_threads[kMaxPhase + 1] = { 1, 2, 2, 2, 2 };
- #endif
-
- long gLoopOverhead; // Timer Manager Overhead
-
- /***
- * CNeoBenchDoc
- *
- * This is your document's initialization method.
- * If your document has its own instance variables, initialize
- * them here.
- *
- * The least you need to do is invoke the default method.
- *
- ***/
-
- CNeoBenchDoc::CNeoBenchDoc(const Boolean aPrintable, const Boolean aNewDatabase, const Boolean aRemote)
- : CNeoDocTCL(kNeoBenchSig, kNeoBenchFileType, aPrintable, aNewDatabase)
- {
- short index, j;
-
- /**
- ** Set the button state flag
- **/
- fState = kStop;
- fRefresh = TRUE;
-
- #ifdef qNeoThreads
- fThreadCount = 0;
- #endif
-
- fPhase = kNoPhase; /* No phase yet */
- fIterator = nil;
-
- // These three values are the running values that change
- col_index = kMinCol;
- for (index = kMinCol; index <= kMinCol; index++)
- col_value[index] = 0;
-
- //
- // Init the fields in the array. The default values
- // will be coming from the text in the TextEdit boxes.
- //
-
- for (index = kMinPhase; index <= kMaxPhase; index++) {
- fPhaseInfo[index].dirty = FALSE;
- #ifdef qNeoThreads
- NeoAssert(default_threads[index] <= kMaxThreads);
- fPhaseInfo[index].threadCount = default_threads[index];
- #endif
- fPhaseInfo[index].target = 0;
- fPhaseInfo[index].done = 0;
- fPhaseInfo[index].committed = 0;
- fPhaseInfo[index].soFar = 0;
- }
-
- srand((unsigned int)clock());
- }
-
- /***
- * buildWindow
- *
- * This is the auxiliary window-building method that the
- * NewFile() and OpenFile() methods use to create a window.
- *
- * In this implementation, the argument is the data to display.
- *
- ***/
-
- void CNeoBenchDoc::buildWindow(void)
- {
- CScrollPane *theScrollPane;
- CNeoBenchPane *theMainPane;
- Rect windRect;
-
- /**
- ** First create the window and initialize
- ** it. The first argument is the resource ID
- ** of the window. The second argument specifies
- ** whether the window is a floating window.
- ** The third argument is the window's enclosure; it
- ** should always be gDesktop. The last argument is
- ** the window's supervisor in the Chain of Command;
- ** it should always be the Document object.
- **
- **/
-
- itsWindow = new CWindow();
- itsWindow->IWindow(WINDNeoBench, FALSE, gDesktop, this);
-
- /**
- ** Set the Min and Max value the window can be resized.
- ** Note that we really don't want the user to resize it
- ** so we make the min and max numbers the same.
- **/
- itsWindow->ChangeSize(508, 299);
- SetRect(&windRect, 508, 299, 508, 299);
- itsWindow->SetSizeRect(&windRect);
-
- /**
- ** We are just creating a fixed pane that sits in the
- ** window. And this will become like a modeless dialog
- **/
-
- theMainPane = new(CNeoBenchPane);
- theMainPane->INeoBenchPane(itsWindow, this, 508, 299, 0, 0, sizFIXEDLEFT, sizFIXEDTOP);
- itsMainPane = theMainPane;
- itsGopher = theMainPane;
-
- /**
- ** Use CenterWindow to center the window in the middle
- ** of the screen.
- **/
-
- gDecorator->CenterWindow(itsWindow);
- }
-
- Boolean CNeoBenchDoc::Close(Boolean aQuitting)
- {
- #ifdef qNeoThreads
- killThreads();
- #endif
-
- delete fIterator;
- fIterator = nil;
-
- return inherited::Close(aQuitting);
- }
-
-
- /***
- * DoCommand
- *
- * This is the heart of your document.
- * In this method, you handle all the commands your document
- * deals with.
- *
- * Be sure to call the default method to handle the standard
- * document commands: cmdClose, cmdSave, cmdSaveAs, cmdRevert,
- * cmdPageSetup, cmdPrint, and cmdUndo. To change the way these
- * commands are handled, override the appropriate methods instead
- * of handling them here.
- *
- ***/
-
- void CNeoBenchDoc::DoCommand(long theCommand)
- {
- short index;
- long minPhase;
-
- switch (theCommand) {
- case cmdGO:
- //---------------------------------------------------
- // Get the numbers from the Dialog box, and update
- // the fields with the values of the numbers the
- // user has typed in. Also, if the user has typed
- // in out of range numbers, correct them.
- //---------------------------------------------------
- getTargetTotals();
-
- //---------------------------------------------------
- // Set the "fPhase" value to kMinPhase to start the
- // Dawdling process to proceed
- //---------------------------------------------------
- for (index = kMinPhase; index <= kMaxPhase; index++) {
- fPhaseInfo[index].done = 0;
- fPhaseInfo[index].delta = 0;
- fPhaseInfo[index].soFar = 0;
- }
-
- fPhaseInfo[kInsert].delta = ((CNeoDatabase *)itsFile)->getObjectCount(kFillerID, FALSE);
- if (fPhaseInfo[kInsert].delta)
- ((CNeoBenchPane *)itsMainPane)->UpdateCol(kInsert, kSoFar, fPhaseInfo[kInsert].delta);
-
- if (fPhaseInfo[kInsert].delta < fPhaseInfo[kInsert].target)
- fPhase = kMinPhase;
- else
- fPhase = kRandomly;
- break;
-
- case cmdSTOP:
- fPhase = 0;
- break;
-
- default:
- inherited::DoCommand(theCommand);
- break;
- }
- }
-
- /***
- * NewFile
- *
- * When the user chooses New from the File menu, the createDocument
- * method in your application will call the newly created document's
- * NewFile message.
- *
- * This method should begin by calling inherited. After that it might
- * want to title the window and set the default name which will appear
- * in the standard get file dialog. NeoBench calls DoSaveFileAs just
- * so the user doesn't have to choose the Save menu item. Your
- * application may decide otherwise.
- *
- ***/
- void CNeoBenchDoc::NewFile(void)
- {
- inherited::NewFile();
-
- // Append an index number to the default name of the window.
- itsWindow->SetTitle("\pNeoAccess");
-
- // Set the default name which appears in the get file dialog.
- NeoStringCopy("\pNeoBench Results", itsFile->name);
- DoSaveFileAs();
- }
-
- /***
- * OpenFile
- *
- * When the user chooses Open… from the File menu, the OpenDocument
- * method in your application class will let the user choose a file
- * and then send a newly created document this message. The information
- * about the file is in the SFReply record.
- *
- ***/
- void CNeoBenchDoc::OpenFile(SFReply *macSFReply)
- {
- fOpenMode = fsRdWrPerm;
- inherited::OpenFile(macSFReply);
-
- fPhaseInfo[kInsert].delta = ((CNeoDatabase *)itsFile)->getObjectCount(kFillerID, FALSE);
- if (fPhaseInfo[kInsert].delta)
- ((CNeoBenchPane *)itsMainPane)->UpdateCol(kInsert, kSoFar, fPhaseInfo[kInsert].delta);
-
- itsWindow->Select(); /* Don't forget to make the window active */
- }
-
- /******************************************************************************
- Dawdle
- ******************************************************************************/
-
- void CNeoBenchDoc::Dawdle(long *maxSleep)
- {
- short index;
- long loops = 0;
- CNeoBenchPane * pane;
- CNeoDatabaseTCL * database = getDatabase();
-
- NeoUsed(loops);
-
- #ifndef qNeoThreads
- TMTask timer;
-
- if (fState == kStart)
- doSomeWork(fPhase, &timer);
- #endif
-
- pane = (CNeoBenchPane *)itsMainPane;
- NeoAssert(pane);
- for (index = kMinPhase; index <= kMaxPhase; index++) {
- if (fPhaseInfo[index].dirty) {
- pane->UpdateCol(index, kSoFar, fPhaseInfo[index].delta + fPhaseInfo[index].committed);
- pane->UpdateCol(index, kPerRecord, (fPhaseInfo[index].soFar / (fPhaseInfo[index].committed ? fPhaseInfo[index].committed : 1)));
- pane->UpdateCol(index, kTotal, fPhaseInfo[index].soFar);
- fPhaseInfo[index].dirty = FALSE;
- }
- fRefresh = FALSE;
- }
-
- if (fPhase > kMaxPhase)
- setState(kStop);
-
- if (fPhase == kNoPhase &&
- database->isOpen()) {
- database->commit(TRUE);
- setDirty(FALSE);
- }
-
- #ifdef qNeoThreads
- loops = 0;
- while (!fRefresh) {
- CNeoThreadNative::Yield();
- #ifdef qNeoDebug
- loops++;
- if (loops > 1000) {
- loops = 0;
- break;
- }
- #endif
- }
- #endif
- }
-
- /******************************************************************************
- Dawdle
- ******************************************************************************/
-
- void CNeoBenchDoc::doSomeWork(const short aPhase, TMTask *aTimer)
- {
- long done;
- long IveDone = 0;
- long delta;
- long quantum;
- NeoID id;
- CNeoPersist * object;
- CNeoDatabase * oldDatabase = gNeoDatabase;
- CNeoDatabase * database = getDatabase();
- TMTask updateTask;
-
- #ifdef qNeoThreads
- quantum = 500 * fPhaseInfo[aPhase].threadCount;
- #else
- quantum = 500;
- #endif
- if (fPhaseInfo[aPhase].delta + fPhaseInfo[aPhase].done < fPhaseInfo[aPhase].target) {
- gNeoDatabase = database;
-
- updateTask.tmAddr = nil;
- updateTask.qType = 0;
- updateTask.tmCount = 0;
- updateTask.tmWakeUp = 0;
- updateTask.tmReserved = 0;
- InsXTime((QElem *)&updateTask);
- PrimeTime((QElem *)&updateTask, quantum);
-
- aTimer->tmAddr = nil;
- aTimer->qType = 0;
- aTimer->tmCount = 0;
- aTimer->tmWakeUp = 0;
- aTimer->tmReserved = 0;
- InsXTime((QElem *)aTimer);
- PrimeTime((QElem *)aTimer, k30MicroMinutes);
-
- while ((updateTask.qType&0x8000) &&
- (fPhaseInfo[aPhase].delta + fPhaseInfo[aPhase].done < fPhaseInfo[aPhase].target)) {
-
- fPhaseInfo[aPhase].done++;
- IveDone++;
-
- switch (aPhase) {
- case kInsert:
- /*------------------------------------------------------*/
- /* Perform the code for record insertion sequence */
- /*------------------------------------------------------*/
- object = new CFiller;
- FailNIL(object);
- delta = fPhaseInfo[kInsert].delta;
- done = fPhaseInfo[kInsert].done;
- object->fID = delta + done;
- database->addObject(object);
- object->unrefer();
- if (delta + done == fPhaseInfo[kInsert].target) {
- if (database->isOpen())
- database->commit(FALSE);
- setDirty(FALSE);
- }
- break;
-
- case kRandomly:
- /*------------------------------------------------------*/
- /* Perform the code for randomly searching sequence */
- /*------------------------------------------------------*/
- id = (rand()&0x7FFFFFFF) % fPhaseInfo[kInsert].target;
- if (!id)
- id = fPhaseInfo[kInsert].target / 2;
- object = (CFiller *)CFiller::FindByID(database, kFillerID, id, FALSE, nil, nil);
- NeoAssert(object);
- object->unrefer();
- break;
-
- case kSerially:
- /*------------------------------------------------------*/
- /* Serially iterate over a class of objects */
- /*------------------------------------------------------*/
- if (fIterator) {
- object = fIterator->nextObject();
- if (!object) {
- fIterator->reset();
- object = fIterator->currentObject();
- }
- }
- else {
- fIterator = new CNeoIndexIterator(database, kFillerID, nil, FALSE, FALSE);
- object = fIterator->currentObject();
- }
- NeoAssert(object);
- break;
-
- case kChange:
- /*------------------------------------------------------*/
- /* Perform the code for Change sequence here */
- /*------------------------------------------------------*/
- if (fIterator) {
- object = fIterator->nextObject();
- if (!object) {
- fIterator->reset();
- object = fIterator->currentObject();
- }
- }
- else {
- fIterator = new CNeoIndexIterator(database, kFillerID);
- object = fIterator->currentObject();
- }
- NeoAssert(object);
- object->autoReferTo();
- object->setDirty();
- object->autoUnrefer();
- database->setDirty();
- break;
-
- case kDelete:
- /*------------------------------------------------------*/
- /* Perform the code for Delete sequencing here */
- /*------------------------------------------------------*/
- if (!fIterator)
- fIterator = new CNeoIndexIterator(database, kFillerID);
- object = fIterator->currentObject();
- NeoAssert(object);
- object->autoReferTo();
- fIterator->removeCurrent();
- object->autoUnrefer();
- break;
- }
- }
-
- if (database->isOpen() &&
- database->isDirty() &&
- CNeoPersist::FCacheUsed > (CNeoPersist::FCacheSize>>1)) {
- database->commit(FALSE);
- database->setDirty(FALSE);
- }
-
- RmvTime((QElem *)aTimer);
- RmvTime((QElem *)&updateTask);
-
- if (aTimer->tmCount > 0)
- fPhaseInfo[aPhase].soFar += -(k30MicroMinutes + aTimer->tmCount * 1000) - gLoopOverhead;
- else
- fPhaseInfo[aPhase].soFar += -(k30MicroMinutes - aTimer->tmCount) - gLoopOverhead;
- fPhaseInfo[aPhase].committed += IveDone;
- fPhaseInfo[aPhase].dirty = TRUE;
-
- gNeoDatabase = oldDatabase;
- }
- else {
- setPhase(aPhase +1);
- if (fIterator) {
- fIterator->setForward(!fIterator->isForward());
- fIterator->reset();
- }
- }
- }
-
- /****************************************************************************
- getTargetTotals - This method gets the target totals from the TextBoxes
- in the main dialog for each of the 5 phases. If there is any of the
- totals that are out of range, the text in the TextBoxes will be adjusted
- to be within range.
- *****************************************************************************/
- void CNeoBenchDoc::getTargetTotals(void)
- {
- short index;
- CNeoBenchPane *pane;
-
- pane = (CNeoBenchPane *)itsMainPane;
-
- // For each of the phases, get the info into the structure.
-
- for (index = kMinPhase; index <= kMaxPhase; index++) {
- fPhaseInfo[index].target = pane->GetTotalNum(index);
- }
- }
-
- Boolean CNeoBenchDoc::getState(void)
- {
- return fState;
- }
-
- #ifdef qNeoThreads
- void CNeoBenchDoc::killThreads(void)
- {
- short index;
-
- for (index = 0; index < kMaxThreads; index++) {
- if (fThreadInfo[index].state == kAlive) {
- NeoAssert(fThreadInfo[index].thread);
- fThreadInfo[index].state = kDie;
- CNeoThreadNative::Yield(fThreadInfo[index].thread);
- fThreadInfo[index].thread = nil;
- }
- }
- }
- #endif
-
- void CNeoBenchDoc::setState(const Boolean aState)
- {
- short index;
- short phase;
-
- if (aState == kStop) {
- #ifdef qNeoThreads
- killThreads();
- #endif
- phase = kNoPhase;
- }
- else {
- getTargetTotals();
- for (index = kMinPhase; index <= kMaxPhase; index++) {
- fPhaseInfo[index].done = 0;
- fPhaseInfo[index].committed = 0;
- fPhaseInfo[index].delta = 0;
- fPhaseInfo[index].soFar = 0;
- }
-
- fPhaseInfo[kInsert].delta = getDatabase()->getObjectCount(kFillerID, TRUE);
- if (fPhaseInfo[kInsert].delta)
- ((CNeoBenchPane *)itsMainPane)->UpdateCol(kInsert, kSoFar, fPhaseInfo[kInsert].delta);
-
- if (fPhaseInfo[kInsert].delta < fPhaseInfo[kInsert].target)
- phase = kMinPhase;
- else
- phase = kRandomly;
- }
-
- fState = aState;
-
- setPhase(phase);
- }
-
- void CNeoBenchDoc::setPhase(const short aPhase)
- {
- #ifdef qNeoThreads
- short index;
- short count;
-
- if (aPhase >= kMinPhase &&
- aPhase <= kMaxPhase)
- count = fPhaseInfo[aPhase].threadCount;
- else
- count = 0;
-
- for (index = 0; index < count; index++) {
- fThreadInfo[index].document = this;
- fThreadInfo[index].phase = aPhase;
- fThreadInfo[index].state = kAlive;
- if (index >= fThreadCount) {
- fThreadInfo[index].thread = new CBenchThread(&fThreadInfo[index]);
- fThreadCount++;
- fThreadInfo[index].thread->resume();
- }
- }
-
- for (index = fThreadCount; index > count; index--)
- fThreadInfo[index].state = kDie;
- #endif
-
- fPhase = aPhase;
- }
-
- void CNeoBenchDoc::ProviderChanged(CCollaborator *aProvider, long aReason, void* aParam)
- {
- short loops;
- Size size;
- CNeoPersist * object;
- CNeoPersist * parent;
-
- switch (aReason) {
- case NeoAppNeedMemory:
- size = (Size)aParam;
- if (itsFile &&
- (Size)aParam) {
-
- if (dirty) {
- ((CNeoDatabase *)itsFile)->commit(FALSE);
- dirty = FALSE;
- }
-
- if (fPhase == kRandomly) {
- loops = 1;
- do {
- CNeoDatabase::FPurgeLevel = loops;
- CNeoDatabase::FPurgeMin = fPhaseInfo[kInsert].target / 16;
- CNeoDatabase::FPurgeDelta = CNeoDatabase::FPurgeMin / 2;
- loops++;
- } while (!((CNeoDatabase *)itsFile)->purge(size) &&
- MaxBlock() < size);
- return;
- }
- if (fPhase == kInsert)
- CNeoDatabase::FPurgeMin = 2000;
- else
- CNeoDatabase::FPurgeMin = 200;
- CNeoDatabase::FPurgeDelta = CNeoDatabase::FPurgeMin / 4;
- CNeoDatabase::FPurgeLevel = 3;
- ((CNeoDatabase *)itsFile)->purge(size);
- if (MaxBlock() < size)
- ((CNeoDatabase *)itsFile)->purge(size);
- }
- break;
-
- default:
- inherited::ProviderChanged(aProvider, aReason, aParam);
- break;
- }
- }
-
- #ifdef qNeoThreads
- CBenchThread::CBenchThread(ThreadInfo *aInfo, const NeoThreadType aType, void **aArg, const Size aStackSize, const NeoThreadOptions aOptions)
- : CNeoThreadNative(aType, aArg, aStackSize, aOptions)
- {
- fSetTimer = FALSE;
- fInfo = aInfo;
- }
-
- long CBenchThread::run(void)
- {
- while (fInfo->state == kAlive) {
- fInfo->document->doSomeWork(fInfo->phase, &fTimer);
-
- Yield();
- }
-
- fInfo->thread = nil;
-
- return fResult;
- }
-
- // ---------------------------------------------------------------------------
- // • handleSwapIn
- // ---------------------------------------------------------------------------
- // Callback to the Thread Manager.
- //
- void CBenchThread::handleSwapIn(void)
- {
- inherited::handleSwapIn();
-
- // turn timers back on
- if (fSetTimer) {
- InsXTime((QElem *)&fTimer);
- PrimeTime((QElem *)&fTimer, 0);
- }
- }
-
- // ---------------------------------------------------------------------------
- // • handleSwapOut
- // ---------------------------------------------------------------------------
- // Callback to the Thread Manager.
- //
- void CBenchThread::handleSwapOut(void)
- {
- // turn timers off
- fSetTimer = fTimer.qType&0x8000;
- if (fSetTimer)
- RmvTime((QElem *)&fTimer);
-
- inherited::handleSwapOut();
- }
-
- #endif
-
-